package com.jackstraw.jack_base.util.tenant.aop;

import com.jackstraw.jack_base.util.StringUtil;
import com.jackstraw.jack_base.util.AspectUtil;
import com.jackstraw.jack_base.util.tenant.annotation.TenantCut;
import com.jackstraw.jack_base.util.tenant.contextholder.TenantContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Slf4j
@Aspect
@Component
public class TenantAspect implements Ordered {


    @Autowired
    private StandardEnvironment environment;

    /**
     * TenantCut注解切面
     */
    @Pointcut("@within(com.jackstraw.jack_base.util.tenant.annotation.TenantCut)" +
            "&& execution(* *..service.*.*(..))")
    public void tenantCut() {

    }


    @Around("tenantCut()")
    public Object tenanCutByAround(ProceedingJoinPoint joinPoint) {
        long currentTimeMillis = System.currentTimeMillis();
        String tenantName = null;
        //获取Method
        Method method = AspectUtil.getMethod(joinPoint);
        // 获得目标方法名
        String methodName = method.getName();
        //获取代理的对象
        Class aClass = AspectUtil.getClass(method);
        String className = aClass.getName();
        if (aClass.isAnnotationPresent(TenantCut.class)) {
            TenantCut tenantCut = (TenantCut) aClass.getAnnotation(TenantCut.class);
            tenantName = tenantCut.tenantName();
        }
        /**
         * 获取配置文件内容
         */
        tenantName = this.environment.resolvePlaceholders(tenantName);

        if (StringUtil.StringUtilsBylang3.isEmpty(tenantName)) {
            log.error("AOP环绕通知【时间戳为:{}】=========={}#{}方法执行异常。异常原因为：无法获取租户名称=============>", currentTimeMillis, className, methodName);
            throw new IllegalStateException("AOP环绕通知【时间戳为:" + currentTimeMillis + "】==========" + className + "#" + methodName + "方法执行异常，无法获取租户名称=============>");
        }

        log.info("AOP环绕通知【时间戳为:{}】=========={}#{}方法执行开始，获取的TenantCut切面名称为:[{}]", currentTimeMillis, className, methodName, tenantName);
        TenantContextHolder.set(tenantName);
        Object result = null;
        try {
            //获取参数
            Object[] args = joinPoint.getArgs();
            if (args == null || args.length == 0) {
                result = joinPoint.proceed();
            } else {
                result = joinPoint.proceed(args);
            }
        } catch (Throwable e) {
            log.error("AOP环绕通知【时间戳为:{}】=========={}#{}方法执行异常。异常原因为：{}=============>", currentTimeMillis, className, methodName, e);
            throw new IllegalStateException("AOP环绕通知【时间戳为:" + currentTimeMillis + "】==========" + className + "#" + methodName + "方法执行异常=============>");
        } finally {
            log.info("AOP环绕通知【时间戳为:{}】=========={}#{}方法执行结束", currentTimeMillis, className, methodName);
            TenantContextHolder.clear();
        }
        return result;
    }

    @Override
    public int getOrder() {
        return -1;
    }
}
